﻿#include <learn/ais/ais_auxiliary_curve.h>
#include <learn/ais/ais_auxiliary_point.h>
#include <learn/ais/ais_builder.h>
#include <learn/ais/ais_curve.h>
#include <learn/ais/ais_point.h>
#include <learn/ais/ais_surface.h>
#include <learn/ais/ais_vector.h>

using namespace xi;
using namespace xi::ais;

std::shared_ptr<AIS_Object> AIS_Builder::create_point(const Vec3 &point)
{
    Vec3 x(1.0, 0.0, 0.0);
    Vec3 y(0.0, 1.0, 0.0);
    Vec3 z(0.0, 0.0, 1.0);

    return create_point(point, {x, y, z});
}

std::shared_ptr<AIS_Object> AIS_Builder::create_point(const Vec3 &point, const std::vector<Vec3> &axis)
{
    auto pPoint = std::make_shared<Vec3>(point);
    auto aisPoint = std::make_shared<AIS_Point>(pPoint);

    // 必须在构造时立即创建子节点，防止初始化消息无法传递给子节点
    std::vector<std::shared_ptr<AIS_Vector>> vectors;
    for (auto &v : axis)
    {
        auto vec = std::make_shared<AIS_Vector>(aisPoint->point(), std::make_shared<Vec3>(v));
        vectors.push_back(vec);
    }

    // 隐藏坐标轴
    auto msg = std::make_shared<AIS_ShowMsg>();
    msg->show = false;
    for (auto &vec : vectors)
        vec->handle_msg(msg);

    for (auto &vec : vectors)
        aisPoint->add_child(vec);

    return aisPoint;
}

std::shared_ptr<AIS_Object> AIS_Builder::create_vector(const Vec3 &start, const Vec3 &end)
{
    auto pStart = std::make_shared<Vec3>(start);
    auto pEnd = std::make_shared<Vec3>(end);
    auto aisVector = std::make_shared<AIS_Vector>(pStart, pEnd);

    return aisVector;
}

std::shared_ptr<AIS_Object> AIS_Builder::create_curve(std::shared_ptr<Geom_NonbasisCurve<3>> curve)
{
    return std::make_shared<AIS_Curve>(curve);
}

std::shared_ptr<AIS_Object> AIS_Builder::create_curve(std::shared_ptr<Geom_BasisCurve<3>> curve)
{
    // 用于隐藏辅助点
    auto msg = std::make_shared<AIS_ShowMsg>();
    msg->show = false;

    auto n = curve->pole_num();
    auto aisCurve = std::make_shared<AIS_Curve>(curve);
    auto aisAuxCurve = std::make_shared<AIS_AuxiliaryCurve>();
    for (std::size_t i = 0; i < n; ++i)
    {
        auto getter = [curve, i]() { return curve->pole(i); };
        auto setter = [curve, i](const Vec3 &p) { curve->set_pole(i, p); };
        auto aisPoint = std::make_shared<AIS_AuxiliaryPoint>(getter, setter);
        aisPoint->handle_msg(msg);
        aisCurve->add_child(aisPoint);
        aisAuxCurve->add_point(aisPoint);
    }

    aisAuxCurve->handle_msg(msg);
    aisCurve->add_child(aisAuxCurve);

    return aisCurve;
}

std::shared_ptr<AIS_Object> AIS_Builder::create_curve(std::shared_ptr<Geom_QR_BezierCurve<3>> curve)
{
    // 用于隐藏辅助点
    auto msg = std::make_shared<AIS_ShowMsg>();
    msg->show = false;

    auto aisCurve = std::make_shared<AIS_Curve>(curve);
    auto aisAuxCurve = std::make_shared<AIS_AuxiliaryCurve>();
    std::shared_ptr<AIS_AuxiliaryPoint> midPoint;
    for (std::size_t i = 0; i < 3; ++i)
    {
        auto getter = [curve, i]() { return curve->pole(i); };
        auto setter = [curve, i](const Vec3 &p) { curve->set_pole(i, p); };
        auto aisPoint = std::make_shared<AIS_AuxiliaryPoint>(getter, setter);
        aisPoint->handle_msg(msg);
        aisCurve->add_child(aisPoint);
        aisAuxCurve->add_point(aisPoint);

        if (i == 1)
            midPoint = aisPoint;
    }

    aisAuxCurve->handle_msg(msg);
    aisCurve->add_child(aisAuxCurve);

    // 考虑肩点
    auto setter = [curve](const Vec3 &p) {
        auto p1 = curve->pole(1);
        auto m = (curve->pole(0) + curve->pole(2)) / 2;

        // 投影计算肩点
        auto dp1m = p1 - m;
        auto dpm = p - m;
        if (std::min(dp1m.modulus(), dpm.modulus()) < std::numeric_limits<double>::epsilon())
        {
            curve->set_weight(1, 0);
            return;
        }

        auto s = dot(dpm, dp1m) / (dpm.modulus() * dp1m.modulus());
        curve->set_weight(1, s / (1 - s));
    };

    auto aisShoulder = std::make_shared<AIS_AuxiliaryPoint>([curve]() { return curve->shoulder_point(); }, setter);
    aisShoulder->handle_msg(msg);
    aisCurve->add_child(aisShoulder);

    // 添加辅助线
    auto aisAuxLine = std::make_shared<AIS_AuxiliaryCurve>();
    aisAuxLine->add_point(midPoint);
    aisAuxLine->add_point(aisShoulder);
    aisAuxLine->handle_msg(msg);
    aisCurve->add_child(aisAuxLine);

    return aisCurve;
}

std::shared_ptr<AIS_Object> AIS_Builder::create_surface(std::shared_ptr<Geom_NonbasisSurface<3>> surface)
{
    return std::make_shared<AIS_Surface>(surface);
}

std::shared_ptr<AIS_Object> AIS_Builder::create_surface(std::shared_ptr<Geom_BasisSurface<3>> surface)
{
    // 用于隐藏辅助点
    auto msg = std::make_shared<AIS_ShowMsg>();
    msg->show = false;

    auto nu = surface->u_pole_num();
    auto nv = surface->v_pole_num();
    auto aisSurface = std::make_shared<AIS_Surface>(surface);

    // 不要使用 (nv, std::make_shared<AIS_AuxiliaryCurve>())，这会创建 nv 个相同的 AIS_AuxiliaryCurve 实例
    std::vector<std::shared_ptr<AIS_AuxiliaryCurve>> vCurves(nv);
    for (std::size_t v = 0; v < nv; ++v)
    {
        auto aisAuxVCurve = std::make_shared<AIS_AuxiliaryCurve>();
        vCurves[v] = aisAuxVCurve;
    }

    for (std::size_t u = 0; u < nu; ++u)
    {
        auto aisAuxUCurve = std::make_shared<AIS_AuxiliaryCurve>();
        for (std::size_t v = 0; v < nv; ++v)
        {
            auto getter = [surface, u, v]() { return surface->pole(u, v); };
            auto setter = [surface, u, v](const Vec3 &p) { surface->set_pole(u, v, p); };
            auto aisPoint = std::make_shared<AIS_AuxiliaryPoint>(getter, setter);
            aisPoint->handle_msg(msg);
            aisSurface->add_child(aisPoint);
            aisAuxUCurve->add_point(aisPoint);
            vCurves[v]->add_point(aisPoint);
        }

        aisAuxUCurve->handle_msg(msg);
        aisSurface->add_child(aisAuxUCurve);
    }

    for (auto &curve : vCurves)
    {
        curve->handle_msg(msg);
        aisSurface->add_child(curve);
    }

    return aisSurface;
}